package com.study.studyelasticsearch.practice;

import com.study.studyelasticsearch.client.transportClient.TransportEsClient;
import com.study.studyelasticsearch.practice.bean.Person;
import com.study.studyelasticsearch.util.es.extractor.EsResultExtractor;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

/**
 * 理解term、match、pharse_math
 * @author 吴宇亮 on 2022/5/24 14:29
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class PraticePerson {

    private static final Logger log = LoggerFactory.getLogger(PraticePerson.class);

    @Autowired
    private TransportEsClient transportClient;
    @Autowired
    private EsResultExtractor<Person> esHitExtractor;

    // # 查询名字为林更的人
    @Test
    public void test01(){
        // 这个是查询不出来的，因为”林更“的doc被分词为索引”林“、”更“，然后term是表示对查询条件"林更"不分词，而“林更”匹配不上任意一个索引
//        "GET /study-person/_search\n" +
//                "{\n" +
//                "  \"query\": {\n" +
//                "    \"term\": {\n" +
//                "      \"name\": {\n" +
//                "        \"value\": \"林更\"\n" +
//                "      }\n" +
//                "    }\n" +
//                "  }\n" +
//                "}"

        // 这个会将名字带有 林 和 更 的doc都查出来。首先doc都被索引成"林"、“更”。然后match会对查询条件进行分词在查询，查询条件分词为"林"，"更"，所以doc里带有林、更的都被查询出来
//        "GET /study-person/_search\n" +
//                "{\n" +
//                "  \"query\": {\n" +
//                "    \"match\": {\n" +
//                "      \"name\": \"林更\"\n" +
//                "    }\n" +
//                "  }\n" +
//                "}"


//        为什么这个也可以查询出来？打开profile就可以很清楚得看到查询流程了。
//        当match的字段类型是keyword，对输入也不会进行分词；如果match的字段是text，则会对输入进行分词
//        "GET /study-person/_search\n" +
//                "{\n" +
//                "  \"query\": {\n" +
//                "    \"match\": {\n" +
//                "      \"name.keyword\": \"林更\"\n" +
//                "    }\n" +
//                "  }\n" +
//                "}"

        SearchRequest request = new SearchRequest().indices(InitPraticeData.personIndexName);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder()
                .query(new TermQueryBuilder("name", "林更"));
        request.source(sourceBuilder);
        SearchResponse searchResponse = transportClient.getClient().search(request).actionGet();
        for (SearchHit hit : searchResponse.getHits()) {
            System.out.println(hit);
        }

        // boost是搜索的权重
        System.out.println(request.source().toString());
    }

    // # 找出带有 "林更" 的记录，包括 "小林更新", 但不包含 "林有更"
    @Test
    public void test02(){
        // 思考下default_field为name.keyword结果才是正确的，为name结果为空，为什么？
        // 因为当要搜索的字段为name，那么name对应的索引有：林、更、新，然后每一个都没有匹配上正则/.*林更.*/，所以一个也搜索不出（拿索引去匹配正则）
        // 如果要搜索的字段为name.key，则会拿name的整个值去匹配正则，能匹配上的就展示出来（拿keyword去匹配正则）
//        "GET /study-person/_search\n" +
//                "{\n" +
//                "  \"query\": {\n" +
//                "    \"query_string\": {\n" +
//                "      \"default_field\": \"name.keyword\",\n" +
//                "      \"query\": \"/.*林更.*/\"\n" +
//                "    }\n" +
//                "  },\n" +
//                "  \"profile\": \"true\"\n" +
//                "}";

        SearchRequestBuilder requestBuilder = transportClient.getClient().prepareSearch(InitPraticeData.personIndexName);
        SearchSourceBuilder source = new SearchSourceBuilder().query(new QueryStringQueryBuilder("/.*林更.*/").defaultField("name.keyword"));
        requestBuilder.setSource(source);

        log.info("\nGET /{}/_search \n{}", InitPraticeData.personIndexName, source);
        SearchResponse searchResponse = requestBuilder.get();
        for (SearchHit hit : searchResponse.getHits()) {
            System.out.println(hit);
        }
    }

    // # 找出名字不带有"更新"的记录
    @Test
    public void test03(){
        // 思考下default_field为name.keyword结果才是正确的，为name结果为空，为什么？
        // 因为当要搜索的字段为name，那么name对应的索引有：林、更、新，然后每一个都没有匹配上正则/.*林更.*/，所以一个也搜索不出（拿索引去匹配正则）
        // 如果要搜索的字段为name.key，则会拿name的整个值去匹配正则，能匹配上的就展示出来（拿keyword去匹配正则）
//        "GET /study-person/_search\n" +
//                "{\n" +
//                "  \"query\": {\n" +
//                "    \"query_string\": {\n" +
//                "      \"default_field\": \"name.keyword\",\n" +
//                "      \"query\": \"/.*林更.*/\"\n" +
//                "    }\n" +
//                "  },\n" +
//                "  \"profile\": \"true\"\n" +
//                "}";

        SearchRequestBuilder requestBuilder = transportClient.getClient().prepareSearch(InitPraticeData.personIndexName);
        SearchSourceBuilder source = new SearchSourceBuilder().query(new QueryStringQueryBuilder("/.*林更.*/").defaultField("name.keyword"));
        requestBuilder.setSource(source);
        log.info("\nGET /{}/_search \n{}", InitPraticeData.personIndexName, source);
        SearchResponse searchResponse = requestBuilder.get();
        // 提取结果
        List<Person> result = esHitExtractor.extract(searchResponse, Person.class);
        for (Person person : result) {
            System.out.println(person);
        }
    }

    // 这个可以查出来很多 名字含有林的人，因为term是对输入不分词，然后如果跟doc的其中一个索引就返回true
//    "GET /study-person/_search
//    {
//        "query": {
//        "term": {
//            "name": {
//                "value": "林"
//            }
//        }
//    },
//        "profile": "true"
//    }"



}
